<template>
    <div class="search-box">
        <div class="flex">
            <div>
                <el-icon>
                    <Search />
                </el-icon><span>筛选搜索</span>
            </div>
            <div>
                <el-button @click="resetForm">重置</el-button>
                <el-button @click="submitFn" type="primary">查询搜索</el-button>
            </div>
        </div>
        <div style="padding-top: 20px">
            <!-- 在input里面回车会造成刷新，大家今晚可以尝试解决一下 -->
            <!--  如果希望阻止这一默认行为，可以在 <el-form> 标签上添加 @submit.prevent。 -->
            <!-- model  表单数据对象 -->
            <el-form @submit.prevent="submitFn" ref="searchFormRef" :model="listParams">
                <el-form-item prop="keyword" label="账号/姓名:" label-width="120px">
                    <el-input v-model="listParams.keyword" @change="changeKeyword"></el-input>
                </el-form-item>
            </el-form>
        </div>
    </div>
    <!-- 添加用户按钮 -->
    <div class="add-box">
        <el-button type="primary" @click="addUser">添加</el-button>
    </div>
    <!-- 表格 -->
    <el-table :data="tableData" style="width: 100%">
        <!-- prop接收父子传值的 -->
        <el-table-column prop="id" label="编号" width="80"> </el-table-column>
        <el-table-column prop="username" label="账号" width="150"></el-table-column>
        <el-table-column prop="nickName" label="姓名" width="150"></el-table-column>
        <el-table-column prop="email" label="邮箱" width="180"></el-table-column>
        <el-table-column prop="createTime" label="创建时间">
            <template #default="scope">
                {{ fomatDate(scope.row.createTime) }}
            </template>
        </el-table-column>
        <el-table-column prop="loginTime" label="登录时间">
            <template #default="scope">
                {{ fomatDate(scope.row.loginTime) }}
            </template>
        </el-table-column>
        <el-table-column prop="status" label="是否启用" width="110">
            <!-- 通过插件得到的scope.row是每一列里面的 数据对象 -->
            <template #default="scope">
                <!-- 判断按钮的开关情况对应哪一个值 -->
                <el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0"
                    @change="changeHandle(scope.row)" />
            </template>
        </el-table-column>
        <el-table-column label="操作">
            <template #default="scope">
                <el-button type="primary" link @click="handleEdit(scope.row.id)">分配角色</el-button>
                <el-button type="primary" link @click="handleEditUser(scope.row.id)">编辑</el-button>
            </template>
        </el-table-column>
    </el-table>
    <!-- 如果只有某个组件需要汉化，这么包着就行 -->
    <ElConfigProvider :locale="zhCn">
        <el-pagination v-model:currentPage="listParams.pageNum" v-model:page-size="listParams.pageSize" background
            layout="total, sizes, prev, pager, next ,jumper" :total="total" @size-change="pageSizeChagne"
            @current-change="currentChagne" :page-sizes="[10, 20, 50, 100]" />
    </ElConfigProvider>

    <!-- 添加用户弹窗 -->
    <EditUser :show="showEditUser" @hideEdit="hideEdit" @refresh="getList" :nowId="nowId" />

    <!-- 分配用户的弹窗 -->
    <AllocRole :Roleshow="Roleshow" @hideRole="hideRole" :allocRoleId="allocRoleId" />
</template>
  
<script lang="ts" setup>
import EditUser from "./components/EditUser.vue"
import AllocRole from "./components/AllocRole.vue"
import { ElConfigProvider, FormInstance } from "element-plus";
// element里面就已经帮我们准备好的 不同语言包，直接使用就行
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import { user } from "@/request";
import { reactive, ref, toRefs } from "vue";
import { fomatDate } from "@/utils";
import { ElMessage, rowContextKey } from "element-plus";
import { Search } from "@element-plus/icons-vue";

interface IState {
    tableData: IUserModel[];
    listParams: IUserListParams;
    total: number;
}
// 一般如果遇上有部分数据是复杂类型，希望它们是响应式的，一般先准备一个总的state
const state = reactive<IState>({
    tableData: [],
    listParams: {
        // input 内容
        keyword: "",
        pageNum: 1,
        pageSize: 10,
    },
    total: 0,
});
// 分配角色的显示隐藏
const Roleshow = ref(false)

const searchFormRef = ref<FormInstance>();

const getList = () => {
    // 搜索跟之前第一次请求的不同就是 搜索要带 输入框里面的数据
    user.getUserListApi(state.listParams).then((res) => {
        if (res.code === 200) {
            state.tableData = res.data.list;
            state.total = res.data.total;
        }
    });
};
// 一开始的时候需要先调用一次
getList();

// 点击搜索按钮查询
const submitFn = () => {
    // 重新请求一个数组回来把数据渲染到表格里面
    // 搜索一定要把 页码调整为第一页
    state.listParams.pageNum = 1;
    getList();
};

// 点击了分配角色的id
const allocRoleId = ref(0);
// 点击分配角色
const handleEdit = (id: number) => {
    Roleshow.value = true
    allocRoleId.value = id
};

// 定义当前点击的id
const nowId = ref(0)
// 点击编辑获取id
const handleEditUser = (id: number) => {
    // console.log(id);
    nowId.value = id
    showEditUser.value = true;
};

// input 回车事件
const changeKeyword = () => {
    getList();
}

const changeHandle = (row: IUserModel) => {
    user.updateUserStatusApi({
        id: row.id,
        status: row.status,
    }).then((res) => {
        ElMessage({
            message: res.message,
            type: res.code === 200 ? "success" : "error",
        });
    }).catch(err => {
        // 如果请求失败，会走catch
        // 把 switch 恢复成之前的状态
        // 方式1
        row.status = row.status === 1 ? 0 : 1
        // 方式2
        // let target = state.tableData.find((item) => item.id === row.id)
        // target && (target.status = row.status === 1 ? 0 : 1)
    });
};

// 重置按钮
// 1. 点击事件
// 2. 需要给el-from表单组件添加一个ref属性，得到该组件的实例
// 3. 点击的时候调用 组件实例的resetFields方法进行重置
// 4. 前提是 给 el-from 设置了 model 属性
// 5. 还需要给 el-form-item 设置相应的 prop 属性
const resetForm = () => {
    // console.log('重置');
    // 获取到form 表单的组件实例
    // resetField   对该表单项进行重置，将其值重置为初始值并移除校验结果
    searchFormRef.value?.resetFields()
    getList();
}


const pageSizeChagne = (val: number) => {
    //   console.log(val);
    // 组件使用的是 v-model绑定的 listParams.pageSize 无需再次修改
    //   console.log(state.listParams);
    //   当 面容量变化的时候，需要把页面上的数据 变成对应的数量
    //   但是一定要注意一个问题，现在如果已经在最后一页，最后一页数据，只有5条，想加载更多的条数就没有了 - 提示用户 - 今晚想想怎么做
    getList();
    // 如果当前已经是最一页，我们之前希望有提示，但是基于我们之前数据没有更多了，数据也不会更新才有这样的一个需求
    // 但是现在我们完成后续的工作之后，已经没有这个问题了
    // 目前存在的问题是： 修改了 pageSize 之后，发两次请求，目前没有太好的办法解决，先放着
};

const currentChagne = (val: number) => {
    // val是新的页码
    // console.log(val);
    //   获取新的数据进行渲染
    getList();
};

// 控制 EidtUser 组件是否显示的 变量
const showEditUser = ref(false);

// 控制显示
const addUser = () => {
    // 控制 EditUser 显示
    showEditUser.value = true;
};

// 添加用户子传父事件
const hideEdit = () => {
    showEditUser.value = false;
    nowId.value = 0
}

// 分配角色部分
// 隐藏分配角色弹窗
const hideRole = () => {
    // console.log(1);
    Roleshow.value = false
    allocRoleId.value = 0;
}


// const fmtDate = (row: IUserModel) => {
//   // 把row里面的 时间 修改成一个 看起来比较舒服的格式
//   //   console.log(row.createTime);
//   //   如果后端返回的时间是 中国的时间，直接渲染就行，
//   // 但是有时候返回的不是中国的时间，需要我们自己在前端进行处理
//   let date = new Date(row.createTime); // new Date的时候，js会手动帮我们转换为当前时区的时间来进行展示
//   //   date 是一个中国时区的标准时间，可以自己把里面的 年月日，时分秒获取出来进行展示 - 缺点：麻烦，但是全世界通用
//   // 其实还有更加简单的方法 -- 缺点：这个写法只适合固定时区
//   //   date.setHours(date.getHours() + 8);
//   //   return date.toJSON().replace("T", " ").slice(0, 19);

// //  这个方法也行，缺点：要手动把 / 换成 -
//   return date.toLocaleString().replaceAll("/", "-");
// };

// 两个时间的处理逻辑是一样的，可以做一个封装，根据不同的属性来获取时间再格式化
// const fomatDate = (row: IUserModel, key: "createTime" | "loginTime") => {

//     //   如果没有时间，就返回一个空的字符串
//     if (!row[key]) return "";
//     let date = new Date(row[key]);
//     return date.toLocaleString().replaceAll("/", "-");
// };

// const fmtDate = (row: IUserModel) => fomatDate(row, "createTime");
// const fmtDate2 = (row: IUserModel) => fomatDate(row, "loginTime");


// state是一个响应式数据，但是我们如果在 tempatle里面使用 state里面的数据，需要 使用 state 点出来
// 一般会使用 toRefs 把里面的数据解构成多个响应式子数据
let { tableData, listParams, total } = toRefs(state);
</script>

<style lang="less" scoped>
.search-box {
    padding: 20px;
    border: 1px solid #ccc;
    border-radius: 10px;

    .flex {
        display: flex;
        justify-content: space-between;
    }
}

.add-box {
    display: flex;
    justify-content: flex-end;
    padding: 10px;
    margin: 20px;
    border-radius: 10px;
    box-shadow: 0 0 4px 2px #ccc;
}
</style>